/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jfonia.view.symbols;

import java.awt.BasicStroke;
import java.awt.Graphics2D;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.basics.ValueNode;
import org.jfonia.connect5.basics.Node;
import org.jfonia.connect5.basics.Observer;
import org.jfonia.connect5.intervals.BasicDoubleInterval;
import org.jfonia.connect5.relations.Equal;
import org.jfonia.constants.SymbolConstants;

/**
 *
 * @author Rik Bauwens
 */
public class StemSymbol extends RankedStaffSymbol
{
        private BasicDoubleInterval stemInterval;
        private boolean enabled;

        public StemSymbol(ValueNode<Double> frameX, ValueNode<Double> staffY,
                          MutableValueNode<Double> staffBase, MutableValueNode<Double> postStaffBase,
                          ValueNode<Double> xNode, MutableValueNode<Double> widthNode,
                          MutableValueNode<Integer> rankNode, ValueNode<Integer> stemNode,
                          ValueNode<Integer> stemDirectionNode)
        {
                super(frameX, staffY, staffBase, postStaffBase, xNode, widthNode, rankNode);
                //Interval that represents the two y coordinates of the stem,
                //endNode is used for beaming
                stemInterval = new BasicDoubleInterval();
                new Equal<Double>(getYNode(), stemInterval.getBeginNode());
                init(stemNode, stemDirectionNode);
        }
        
        private void init(ValueNode<Integer> stemNode, ValueNode<Integer> stemDirectionNode)
        {
                setStem(stemNode.getValue());
                stemNode.addObserver(new Observer()
                {
                        public void onNotify(Object source)
                        {
                                setStem(((ValueNode<Integer>) source).getValue());
                        }
                });
                setStemDirection(stemDirectionNode.getValue());
                stemDirectionNode.addObserver(new Observer()
                {
                        public void onNotify(Object source)
                        {
                                setStemDirection(((ValueNode<Integer>) source).getValue());
                        }
                });
        }

        public ValueNode<Double> getStemTailNode()
        {
                return stemInterval.getEndNode();
        }
        
        private void setStem(int stemId)
        {
                if(stemId == SymbolConstants.STEM_MINIM || stemId == SymbolConstants.STEM_CROTCHET
                || stemId == SymbolConstants.STEM_QUAVER || stemId == SymbolConstants.STEM_SEMIQUAVER
                || stemId == SymbolConstants.STEM_DEMISEMIQUAVER || stemId == SymbolConstants.STEM_HEMIDEMISEMIQUAVER)
                {
                        enabled = true;
                }
                else
                {
                        enabled = false;
                        stemInterval.setDifference(0);
                }
                updateNodes();
        }

        private void setStemDirection(int stemDirection)
        {
                if(stemDirection == SymbolConstants.STEM_DIRECTION_DOWN)
                        stemInterval.setDifference(SymbolConstants.STEM_LENGTH);
                else if(stemDirection == SymbolConstants.STEM_DIRECTION_UP)
                        stemInterval.setDifference(-SymbolConstants.STEM_LENGTH);
                else
                        stemInterval.setDifference(0);
                updateNodes();
        }

        protected void updateNodes()
        {
                preXNode.setValue(Math.ceil(SymbolConstants.STEM_WIDTH));
                postXNode.setValue(0.0);
                if(stemInterval.getDifference() < 0)
                {
                        preYNode.setValue(-stemInterval.getDifference());
                        postYNode.setValue(0.0);
                }
                else
                {
                        preYNode.setValue(0.0);
                        postYNode.setValue(stemInterval.getDifference());
                }
        }

        @Override
        public void paintSymbol(Graphics2D g)
        {
                super.paintSymbol(g);
                if(enabled)
                {
                        double x = Math.ceil(getX());
                        if(stemInterval.getDifference() < 0)
                            x -= SymbolConstants.STEM_WIDTH;
                        else
                            x += SymbolConstants.STEM_WIDTH;
                        g.setStroke(new BasicStroke(SymbolConstants.STEM_WIDTH));
                        g.drawLine((int) x, (int) Math.ceil(stemInterval.getBegin()),
                                   (int) x, (int) Math.ceil(stemInterval.getEnd()));
                }
        }
}
